/***************************************************************************
 * General Ledger, Copyright (C) 2008 Armin Moradi <feng.shaun@gmail.com>  *
 * http://fengshaun.wordpress.com                                          *
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation; either version 3 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program; if not, write to the Free Software             *
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 US  *
 ***************************************************************************/

#include <iostream>

#include <QtGui>
#include <QtNetwork>

#include "mainwindow.h"
#include "settingsdialog.h"
#include "connectdialog.h"
#include "serverdialog.h"
#include "tictactoe.h"
#include "server.h"
#include "client.h"
#include "counterdockwidget.h"

MainWindow::MainWindow(int w, int h) {
	m_width = w;
	m_height = h;

	m_isServer = false;
	m_isClient = false;

	m_tictactoe = new TicTacToe(QString("---------"), this);
	m_tictactoe->clear();
	m_counterDockWidget = new CounterDockWidget;
	setCentralWidget(m_tictactoe);

	createDockWidgets();
	createActions();
	createToolBars();
	createMenus();
	createStatusBar();
	initVariables();

	setWindowIcon(QIcon(":/images/icon.png"));
	resize(width(), height());
	setWindowTitle("Tic-Tac-Toe");
	readSettings();
}

void MainWindow::initVariables() {
	m_server = NULL;
	m_client = NULL;
	m_port = 0;
	m_host = "";
	m_serverPort = 0;
	m_serverPortLoaded = false;

	m_isServer = false;
	m_isClient = false;

	m_saveServer = false;
	m_saveConnection = false;
	m_saveColors = false;
}

int MainWindow::width() {
	return m_width;
}

int MainWindow::height() {
	return m_height;
}

void MainWindow::createActions() {
	m_newAction = new QAction(tr("&New"), this);
	m_newAction->setIcon(QIcon(":/images/new.png"));
	m_newAction->setShortcut(QKeySequence::New);
	m_newAction->setStatusTip(tr("Start a new game"));
	connect(m_newAction, SIGNAL(triggered()), this, SLOT(newGame()));

	m_exitAction = new QAction(tr("&Exit"), this);
	m_exitAction->setIcon(QIcon(":/images/exit.png"));
	m_exitAction->setShortcut(QString("Ctrl+Q"));
	m_exitAction->setStatusTip(tr("Exit game"));
	connect(m_exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

	m_settingsAction = new QAction(tr("&Preferences..."), this);
	m_settingsAction->setStatusTip(tr("Change game's options"));
	m_settingsAction->setIcon(QIcon(":/images/settings.png"));
	connect(m_settingsAction, SIGNAL(triggered()), this, SLOT(setOptions()));

	m_enableCounterAction = new QAction(tr("Show &counter"), this);
	m_enableCounterAction->setStatusTip(tr("Show counter to keep track of wins/loses"));
	m_enableCounterAction->setCheckable(true);
	connect(m_enableCounterAction, SIGNAL(toggled(bool)), m_counterDockWidget, SLOT(setVisible(bool)));

	m_connectToServerAction = new QAction(tr("&Join..."), this);
	m_connectToServerAction->setStatusTip(tr("Join a game server"));
	m_connectToServerAction->setIcon(QIcon(":/images/connect.png"));
	connect(m_connectToServerAction, SIGNAL(triggered()), this, SLOT(connectToServer()));

	m_createServerAction = new QAction(tr("&Create a server"), this);
	m_createServerAction->setStatusTip(tr("Create a game server"));
	m_createServerAction->setIcon(QIcon(":/images/server.png"));
	connect(m_createServerAction, SIGNAL(triggered()), this, SLOT(createServer()));

	m_aboutAction = new QAction(tr("&About"), this);
	m_aboutAction->setStatusTip(tr("Learn about this game"));
	connect(m_aboutAction, SIGNAL(triggered()), this, SLOT(about()));

	m_aboutQtAction = new QAction(tr("A&bout Qt"), this);
	m_aboutQtAction->setStatusTip(tr("Learn about Qt"));
	connect(m_aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));

	m_reportBugsAction = new QAction(tr("Report Bugs"), this);
	m_reportBugsAction->setStatusTip(tr("Report bugs"));
	connect(m_reportBugsAction, SIGNAL(triggered()), this, SLOT(reportBugs()));
}

void MainWindow::createMenus() {
	m_fileMenu = menuBar()->addMenu(tr("&File"));
	m_fileMenu->addAction(m_newAction);
	m_fileMenu->addSeparator();
	m_fileMenu->addAction(m_exitAction);

	m_optionsMenu = menuBar()->addMenu(tr("&Edit"));
	m_optionsMenu->addAction(m_settingsAction);

	m_viewMenu = menuBar()->addMenu(tr("&View"));
	m_viewMenu->addAction(m_enableCounterAction);

	m_multiMenu = menuBar()->addMenu(tr("&Multiplayer"));
	m_multiMenu->addAction(m_createServerAction);
	m_multiMenu->addAction(m_connectToServerAction);

	m_helpMenu = menuBar()->addMenu(tr("&Help"));
	m_helpMenu->addAction(m_aboutAction);
	m_helpMenu->addAction(m_aboutQtAction);
	m_helpMenu->addAction(m_reportBugsAction);
}

void MainWindow::createToolBars() {
	m_fileToolBar = addToolBar(tr("&File"));
	m_fileToolBar->setObjectName("m_fileToolBar");
	m_fileToolBar->addAction(m_newAction);
	m_fileToolBar->addAction(m_settingsAction);
	m_fileToolBar->addSeparator();
	m_fileToolBar->addAction(m_createServerAction);
	m_fileToolBar->addAction(m_connectToServerAction);
	m_fileToolBar->setIconSize(QSize(22, 22));
}

void MainWindow::createStatusBar() {
	m_statusLabel = new QLabel;
	statusBar()->addWidget(m_statusLabel);
	updateStatusBar();

	connect(m_tictactoe, SIGNAL(playerChanged(int)), this, SLOT(updateStatusBar()));
	connect(m_tictactoe, SIGNAL(filled()), this, SLOT(clearStatusBar()));
	connect(m_tictactoe, SIGNAL(xWon(int, int, int)), this, SLOT(xWon()));
	connect(m_tictactoe, SIGNAL(oWon(int, int, int)), this, SLOT(oWon()));
}

void MainWindow::createDockWidgets() {
	m_counterDockWidget->setObjectName("m_counterDockWidget");
	addDockWidget(Qt::BottomDockWidgetArea, m_counterDockWidget);
	m_counterDockWidget->hide();

	connect(m_counterDockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)),
			m_counterDockWidget->counter(), SLOT(changeLayout(Qt::DockWidgetArea)));
	connect(m_tictactoe, SIGNAL(xWon(int, int, int)), m_counterDockWidget->counter(), SLOT(playerOneWon()));
	connect(m_tictactoe, SIGNAL(oWon(int, int, int)), m_counterDockWidget->counter(), SLOT(playerTwoWon()));
}

void MainWindow::closeEvent(QCloseEvent *event) {
	saveSettings();
	event->accept();
}

void MainWindow::saveSettings() {
	QSettings settings("Armin Moradi", "Tic-Tac-Toe");

	settings.setValue("MainWindow/saveColors", m_saveColors);
	settings.setValue("MainWindow/saveConnection", m_saveConnection);
	settings.setValue("MainWindow/saveServer", m_saveServer);

	settings.setValue("MainWindow/TicTacToe/gridColor", m_tttGridColor);
	settings.setValue("MainWindow/TicTacToe/penColor", m_tttPenColor);
	settings.setValue("MainWindow/TicTacToe/crossColor", m_tttCrossColor);

	settings.setValue("MainWindow/CounterDockWidget/show", m_enableCounterAction->isChecked());
	settings.setValue("MainWindow/geometry", this->saveGeometry());
	settings.setValue("MainWindow/state", this->saveState());

	settings.setValue("MainWindow/connection/ip", m_host);
	settings.setValue("MainWindow/connection/port", m_port);
	
	settings.setValue("MainWindow/server/port", m_serverPort);
	settings.setValue("MainWindow/server/portLoaded", m_serverPortLoaded);
}

void MainWindow::readSettings() {
	QSettings settings("Armin Moradi", "Tic-Tac-Toe");

	m_saveColors = settings.value("MainWindow/saveColors", false).toBool();
	m_saveConnection = settings.value("MainWindow/saveConnection", false).toBool();
	m_saveServer = settings.value("MainWindow/saveServer", false).toBool();

	restoreState(settings.value("MainWindow/state").toByteArray());
	restoreGeometry(settings.value("MainWindow/geometry").toByteArray());
	
	m_enableCounterAction->setChecked(settings.value("MainWindow/CounterDockWidget/show").toBool());

	if (m_saveColors) {
		m_tttGridColor = settings.value("MainWindow/TicTacToe/gridColor", SettingsDialog::defaultColor)
								 .value<QColor>();
		m_tttPenColor = settings.value("MainWindow/TicTacToe/penColor", SettingsDialog::defaultColor)
								.value<QColor>();
		m_tttCrossColor = settings.value("MainWindow/TicTacToe/crossColor", SettingsDialog::defaultColor)
								  .value<QColor>();
	}

	if (m_saveConnection) {
		m_host = settings.value("MainWindow/connection/ip", QString("")).toString();
		m_port = quint16(settings.value("MainWindow/connection/port", 0).toInt());
	}

	if (m_saveServer) {
		m_serverPort = quint16(settings.value("MainWindow/server/port", 0).toInt());
		m_serverPortLoaded = settings.value("MainWindow/server/portLoaded", false).toBool();
	}

	m_tictactoe->setColors(m_tttGridColor, m_tttPenColor, m_tttCrossColor);
}

void MainWindow::updateStatusBar() {
	QString label;
	if (m_isServer) {
		if (m_tictactoe->player() == 1)
			m_statusLabel->setText(tr("Your turn"));
		else
			m_statusLabel->setText(tr("Remote player's turn"));
	} else if (m_isClient) {
		if (m_tictactoe->player() == 2)
			m_statusLabel->setText(tr("Remote player's turn"));
		else
			m_statusLabel->setText(tr("Your turn"));
	} else {
		if (m_tictactoe->player() == 1)
			m_statusLabel->setText(tr("Player 1's turn"));
		else
			m_statusLabel->setText(tr("Player 2's turn"));
	}
}

void MainWindow::clearStatusBar() {
	m_statusLabel->setText("");
}

void MainWindow::xWon() {
	m_statusLabel->setText("Player 1 has won");
}

void MainWindow::oWon() {
	m_statusLabel->setText("Player 2 has won");
}

void MainWindow::newGame() {
	m_tictactoe->clear();
	m_statusLabel->setText("");
}

void MainWindow::about() {
	QMessageBox::about(this, tr("About Tic Tac Toe"),
					   tr("<h2>Tic-Tac-Toe 0.3</h2>"
					      "<p>Copyright &copy; 2008 Armin Moradi"
						  "<p>Tic-Tac-Toe is a simple multiplayer tic-tac-toe game"
						  "<p> "
						  "<p>website: http://code.google.com/p/onlintictactoe"
						  ));
}

void MainWindow::center() {
	desktop = QApplication::desktop();

	int x = (desktop->width() - this->width()) / 2;
	int y = (desktop->height() - this->height()) / 2;

	move(x, y);
}

void MainWindow::setOptions() {
	SettingsDialog dialog;
	if (dialog.exec()) {
		m_saveColors = dialog.saveColors();
		m_saveServer = dialog.saveServer();
		m_saveConnection = dialog.saveConnection();

		m_serverPort = quint16(dialog.serverPort());
		m_serverPortLoaded = dialog.serverPortLoaded();
		m_host = dialog.connectionIp();
		m_port = quint16(dialog.connectionPort());

		m_tttGridColor = dialog.gridColor();
		m_tttPenColor = dialog.penColor();
		m_tttCrossColor = dialog.crossColor();

		m_tictactoe->setColors(m_tttGridColor, m_tttPenColor, m_tttCrossColor);
	}
	update();
}

void MainWindow::connectToServer() {
	m_isClient = true;

	if (m_port == 0 || m_host.isEmpty()) {
		ConnectDialog dialog;
		if (dialog.exec()) {
			m_host = dialog.host();
			m_port = dialog.port();
		} else {
			return;
		}
	}
	std::cout << "Connecting to server..." << std::endl;
	m_client = new Client(this);

	connect(m_client, SIGNAL(connected()), this, SLOT(connected()));
	connect(m_client, SIGNAL(readDone(int)), this, SLOT(updateTicTacToe(int)));
	connect(m_tictactoe, SIGNAL(stateUpdated(int)), m_client, SLOT(send(int)));
	
	m_client->connectToHost(m_host, m_port);
}

void MainWindow::createServer() {
	m_isServer = true;
	m_server = new Server(this);

	if (!m_serverPortLoaded) {
		ServerDialog dialog;
		if (dialog.exec()) {
			m_serverPort = dialog.port();
		} else {
			return;
		}
	}

	if (m_serverPort > 0) {
		m_server->listen(QHostAddress::Any, m_serverPort);
	} else {
		m_server->listen();
	}
	if (!m_server->isListening()) {
		QMessageBox::critical(this, tr("Tic-Tac-Tie"),
							  tr("Could not connect:\n%1").arg(m_server->errorString()),
							  QMessageBox::Ok);
		return;
	}
	std::cout << "Awaiting connections on port " << int(m_server->serverPort()) << std::endl;
	m_statusLabel->setText(tr("Awaiting connections on port %1").arg(m_server->serverPort()));
	connect(m_server, SIGNAL(newConnection()), this, SLOT(connected()));
	connect(m_server, SIGNAL(readDone(int)), this, SLOT(updateTicTacToe(int)));
	connect(m_tictactoe, SIGNAL(stateUpdated(int)), m_server, SLOT(send(int)));
}

void MainWindow::connected() {
	std::cout << "Connected" << std::endl;
	m_tictactoe->clear_suppress();
	m_counterDockWidget->counter()->reset();
	if (m_isServer) {
		m_counterDockWidget->counter()->setNetworkPlay(true, 1);
		m_statusLabel->setText(tr("You are now player X"));
		m_tictactoe->setXOnly();
	} else {
		m_counterDockWidget->counter()->setNetworkPlay(true, 2);
		m_statusLabel->setText(tr("You are now player O"));
		m_tictactoe->setOOnly();
	}
}

void MainWindow::updateTicTacToe(int pos) {
	if (pos > 9) {
		m_tictactoe->clear_suppress();
		m_statusLabel->setText("");
	} else {
		if (m_isServer)
			m_tictactoe->setState_suppress(pos, 'O');
		else
			m_tictactoe->setState_suppress(pos, 'X');
	}
	update();
}

void MainWindow::reportBugs() {
	QMessageBox::information(this, tr("Tic-Tac-Toe"),
							 tr("You can file a bug report on:\n"
								"http://code.google.com/p/onlinetictactoe/issues/list\n\n"
								"Thank you"),
							 QMessageBox::Ok);
}
